#!/usr/bin/perl
use strict;
use warnings;

# setup repo-specific hooks

use lib $ENV{GL_LIBDIR};
use Gitolite::Rc;
use Gitolite::Common;

_die "repo-specific-hooks: LOCAL_CODE not defined in rc" unless $rc{LOCAL_CODE};
_die "repo-specific-hooks: '$rc{LOCAL_CODE}/hooks/repo-specific' does not exist or is not a directory" unless -d "$rc{LOCAL_CODE}/hooks/repo-specific";

_chdir( $ENV{GL_REPO_BASE} );

@ARGV = ("gitolite list-phy-repos | gitolite git-config -ev -r % gitolite-options\\.hook\\. |");

my $driver = "$rc{LOCAL_CODE}/hooks/multi-hook-driver";
# Hook Driver
{
    local $/ = undef;
    my $hook_text = <DATA>;
    _print( $driver, $hook_text );
    chmod 0755, $driver;
}

while (<>) {
    chomp;
    my ( $repo, $hook, $codes ) = split /\t/, $_;
    $codes ||= '';

    # we don't allow fiddling with the admin repo
    if ( $repo eq 'gitolite-admin' ) {
        _warn "repo-specific-hooks: ignoring attempts to set hooks for the admin repo";
        next;
    }

    # get the hook name
    $hook =~ s/^gitolite-options\.hook\.//;

    unless ( $hook =~ /^(pre-receive|post-receive|post-update)$/ ) {
        _warn "repo-specific-hooks: '$hook' is not allowed, ignoring";
        _warn "    (only pre-receive, post-receive, and post-update are allowed)";
        next;
    }

    my @codes = split /\s+/, $codes;

    my $dst = "$repo.git/hooks/$hook";
    unlink( glob("$dst.*") );

    my $counter = "h00";
    foreach my $code (@codes) {
        if ( $code =~ m(^/|\.\.) ) {
            _warn "repo-specific-hooks: double dot or leading slash not allowed in '$code'";
            next;
        }

        my $src = $rc{LOCAL_CODE} . "/hooks/repo-specific/$code";
        my $dst = "$repo.git/hooks/$hook.$counter-$code";
        unless ( -x $src ) {
            _warn "repo-specific-hooks: '$src' doesn't exist or is not executable";
            next;
        }
        unlink $dst;
        symlink $src, $dst or _warn "could not symlink '$src' to '$dst'";
        $counter++;

        # no sanity checks for multiple overwrites of the same hook
    }

    unlink $dst;
    symlink $driver, $dst or die "could not symlink '$driver' to '$dst'";
}

__DATA__
#/bin/sh

# Determine what input the hook needs
# post-update takes args, pre/post-receive take stdin
type=args
stdin=''
[ $0 != hooks/post-update ] && {
    type=stdin
    stdin=`cat`
}

for h in $0.*; do
    [ -x $h ] || continue
    if [ $type = args ]
    then
        $h $@
    else
        echo "$stdin" | $h
    fi
done
